﻿using System;
using System.Linq.Expressions;
using System.Reflection;

namespace PropertyExpression.Common
{
    public static class ExpressionExtensions
    {
        public static IPropertyExpressionProxy<TEntity, TProperty> ToPropertyExpressionProxy<TEntity, TProperty>(
            this Expression<Func<TEntity, TProperty>> propertyExpression)
        {
            return new PropertyExpressionProxy<TEntity, TProperty>(propertyExpression);
        }

        public static PropertyInfo GetPropertyInfo(this LambdaExpression expression)
        {
            return (PropertyInfo)expression.GetMemberInfo();
        }

        private static MemberInfo GetMemberInfo(this LambdaExpression expression)
        {
            return ((MemberExpression)expression.Body).Member;
        }

        private static TProperty Execute<TProperty, TEntity>(
            this Expression<Func<TEntity, TProperty>> propertyExpression, TEntity entity)
        {
            //TODO: improve performance
            return propertyExpression.Compile()(entity);
        }

        private class PropertyExpressionProxy<TEntity, TProperty> : IPropertyExpressionProxy<TEntity, TProperty>
        {
            private readonly Expression<Func<TEntity, TProperty>> propertyExpression;

            public PropertyExpressionProxy(Expression<Func<TEntity, TProperty>> propertyExpression)
            {
                this.propertyExpression = propertyExpression;
            }

            public PropertyInfo GetPropertyInfo()
            {
                return propertyExpression.GetPropertyInfo();
            }

            public TProperty Execute(TEntity entity)
            {
                return propertyExpression.Execute(entity);
            }
        }
    }
}